package generator;



import generator.utils.TransformDocs;

import java.io.File;
import java.util.List;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;

/**
 * Esta clase es la más general del generador de código gridificado. Se vale de un archivo de configuración para obtener el nombre  de la clase debe gridificar, así como la interface que contiene los métodos que desean gridificarse y el directorio destino de la las clases generadas. Dicho archivo también indica el nombre de la fábrica a través de la cual                     {@link GridCodeGenerator}                     obtendrá la instancia del gridificador que realizará el trabajo de gridificar para un middleware en particular. Existe un archivo de configuración por default llamado confFile_default.xml en la carpeta conf del proyecto. Deberán respetarse los nombres de cada elemento contenidos en dicho archivo para que puedan ser correctamente reconocidos.
 * @uml.dependency   supplier="generator.Gridifier"
 * @uml.dependency   supplier="generator.GridifierFactory"
 */
public class GridCodeGenerator {
	
	/**La clase a gridificar representada como Object*/
	Object jgrimClass;
	
	/**La interface que define los métodos a gridificar representada como Object*/
	Object gridifiableMethodsIF;

	/**
	 * Gridificador que será empleado para efectuar el proceso
	 * @uml.property  name="gridifier"
	 * @uml.associationEnd  
	 */
	Gridifier gridifier;
		
	/**
	 * Directorio destino donde se ubicarán las clases generadas
	 * @uml.property  name="destinationDirectory"
	 */
	String destinationDirectory;
	
	/**Ruta del archivo de configuración por defecto*/
	String defaultConf = "conf//confFile_default.xml";
	
	/**método que inicializa las variables de instancia del generador tales como la clase a 
	 * gridificar, la interface java que contiene los métodos a gridificar, el directorio 
	 * donde se alojarán las clases generadas y el gridificador a utilizar.
	 * @param confFile
	 *			ruta del archivo que contiene las configuraciones
	 **/
	protected void init(String confFile){
		Document configuration = TransformDocs.xmlToDom(new File(confFile));
		XPath xpath = XPathFactory.newInstance().newXPath();
		
		try {
			 String gridifierFactoryName = (String)xpath.evaluate("//GridifierFactory/@name", configuration, XPathConstants.STRING);			 
			 GridifierFactory gridifierFactory = (GridifierFactory)Class.forName(gridifierFactoryName).newInstance();
			 gridifier = gridifierFactory.getGridifierInstance();
					 
			 String jgrimClassPath = (String)xpath.evaluate("//ClassToGridify/@name", configuration, XPathConstants.STRING);
			 this.jgrimClass = gridifierFactory.getClassRepresetation(jgrimClassPath);
			 
			 String gridifiableMethodsIFPath = (String)xpath.evaluate("//MethodsToGridifyIF/@name", configuration, XPathConstants.STRING);
			 this.gridifiableMethodsIF = gridifierFactory.getClassRepresetation(gridifiableMethodsIFPath); 
			 
			 destinationDirectory = (String)xpath.evaluate("//DestinationDirectory/@name", configuration, XPathConstants.STRING);
			 
		} catch (Exception e) {
			System.err.println("Falló inicialización del generador de código. Asegúrese de que el contenido del archivo de configuración sea correcto");
			e.printStackTrace();
		}	
	}
	
	/**Constructor de la clase {@link GridCodeGenerator} que permite obtener una instancia de la clase configurada a partir del archivo
	 * pasado como parámetro
	 * @param confFile
	 * 			archivo de configuración que indica qué clase y qué métodos gridificar así como también el gridificador específico a
	 * 			utilizar, y el destino de los archivos generados.*/
	public GridCodeGenerator(String confFile){
		init(confFile);
	}
	
	/**Constructor de la clase {@link GridCodeGenerator} que permite obtener una instancia de la clase configurada a partir del archivo
	 * confFile_default.xml contenido en la carpeta conf del proyecto*/
	public GridCodeGenerator(){		 
		this.init(defaultConf);				
	}		
	
	/**Método a través del cual se invoca al gridificador para que efectue la tarea de grididicación y luego se escriben las clases
	 * generadas a archivos java.*/
	protected void generate(){
				
		List<WritebleClass> gridClasses = gridifier.gridify(jgrimClass, gridifiableMethodsIF);
		
		for (int i = 0; i < gridClasses.size(); i++)
			gridClasses.get(i).export(destinationDirectory);		
		
	}	

	/**
	 * @return       el directorio destino donde serán alojadas las clases generadas por el gridificador
	 * @uml.property  name="destinationDirectory"
	 */
	public String getDestinationDirectory() {
		return destinationDirectory;
	}
	
	/**@param args 
	 * 			espera recibir 0 o 1 parámetro. En caso de pasarse el parámetro, este corresponde la ruta completa del archivo que
	 * 			contiene la configuración del generador de código.
	 * @see {@link GridCodeGenerator}*/
	public static void main(String[] args) throws Exception {
		GridCodeGenerator gcg;
		if(args.length == 1)
			gcg = new GridCodeGenerator(args[0]);
		else
			gcg = new GridCodeGenerator();
		
		gcg.generate();		
	}

	
	
}
